package com.echo.im.engin.netty.processor.support.in;


import com.echo.im.common.dto.MessageDTO;
import com.echo.im.engin.packet.in.PrivateMessageInPacket;
import com.echo.im.engin.netty.processor.MessageInProcessor;
import com.echo.im.engin.netty.processor.preprocessor.PreprocessorContext;
import com.echo.im.engin.pipeline.PrivateMessageProcessPipeline;
import io.netty.channel.ChannelHandlerContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * @author: echo
 * @time: 2024-08-22
 */
@Component
@RequiredArgsConstructor
public class PrivateMessageInProcessor implements MessageInProcessor<PrivateMessageInPacket> {

    private final PreprocessorContext preprocessorContext;

    private final PrivateMessageProcessPipeline privateMessageProcessPipeline;

    @Override
    public void inProcess(ChannelHandlerContext ctx, PrivateMessageInPacket packet) {
        MessageDTO<PrivateMessageInPacket> messageDTO = new MessageDTO<>(packet);

        //前置处理
        preprocessorContext.doPreprocess(messageDTO);

        privateMessageProcessPipeline.processMessage(messageDTO);
        //这里浓缩了所有精华
        //私聊消息有很多指令  消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10:撤回 11:已读 12:状态变更（上线或者下线）
        //回到原理来说，所有的messageType和内容是高度耦合的，但是我们服务端并不处理这些耦合
        //所有的messageType的语义都放到客户端实现，我们服务端只负责转发
        //然后当我们将消息进行离线存储逻辑或者对方收到并且接收方回复ack的时候，只是对seq进行回复，并且对此seq声明messageId
        //保证了messageId由服务器生成
        //所以这就保证了私聊消息必达

        //然后我们这里还要做一些修改，也是一些元信息
        //消息是否需要赋予id？如果是临时消息，就不要有id了，例如上线下线，也不进入离线逻辑
        //所以 1、是否需要id 2、是否进入离线逻辑 3、是否持久化 4、双方是否需要时好友 等等

        //如果是撤回消息或已读消息这些指令我们直接在仓储的时候修改数据库，没必要直接在我们现在的主要业务中修改数据库
        //TODO 判断此消息是否为重发消息，重发标记务必在服务器做标记，因为客户端不知道这个消息是重发呢还是服务器根本没收到，所以务必是服务端做标记

        // 如果是重发消息，还要判断本地缓存中是否是否已经存在此消息的ack，如果存在，直接伪装 ack
        //感觉还是不行，唯一性必须由客户端生成唯一标识，但是感觉好难，感觉唯一可行的就是，用户消息入库成功，服务器立刻返回ack告知其消息id，说明此消息入库成功，然后再继续等待第二次ack
        //其次就是客户端生成唯一标识
        //服务器生成的标识感觉都不够保证唯一性，因为客服端连续重发了两次无状态的消息，客户端以为是重发，但是服务器不知道啊，服务器怎么知道通过什么去判断幂等性
        //也可以通过在本地缓存一个客户端最大seq的方式来判断是不是重复消息，每次入库，都判断客户端此消息的seq是否大于最大seq，如果更小，那就认为是重复消息

        //其实还可以这样做，我们在入库的时候将seq和messageId都进行入库，如果用户查询消息的时候判断到消息的除了messageId不同，seq已经消息内容全部都相同，则认为此消息是重复消息，不展示
        //如果觉得上述方案可能造成大量重复消息入库，其实还有解决思路，就是我们用两个ack去回复客户，第一个ack是消息入库的ack，此ack告知消息messageId，第二个ack才是真正的ack，告知消息是否已达
        //当用户没有收到第一个ack的时候，进行重发，这时候用seq+内容判断来做去重的兜底，但是可以防止大量重复消息入库，避免将判断丢给客户端



    }



}
